import hashlib, hmac, time, os
from client.http import encode, loadjson, readurl, openurl, randstr, uploadfile
from error import check_status
from client.logger import Log

log = Log('client.kuaipan.api')

def _sign(consumer_secret, http_method='GET', base_uri='', parameters={}, oauth_token_secret=''):
    param = encode(parameters, '.-_~')
    param.sort()
    base_string = "%s&%s&%s" % (http_method, encode(base_uri), encode("&".join(param)))
    key = str(consumer_secret + '&' + oauth_token_secret)
    return hmac.new(key, base_string, hashlib.sha1).digest().encode('base64').rstrip()

class KuaiPanAPI:
    
    def __init__(self, username, userpwd, difftime=0, root='kuaipan', consumer_key='',  oauth_token='', \
                 secret_server='', oauth_callback='http://127.0.0.1', \
                 consumer_secret=None, oauth_token_secret=None, secret_keeper=None):
        self.username = username
        self.userpwd = userpwd
        self.difftime = difftime
        self.root = root
        self.consumer_secret = consumer_secret
        self.consumer_key = consumer_key
        self.sign_by_cleint = consumer_secret is not None
        self.secret_server = secret_server
        self.oauth_callback = oauth_callback
        self.oauth_token = oauth_token or ''
        self.oauth_token_secret = oauth_token_secret or ''
        self.secret_keeper = secret_keeper
        self.charged_dir = ''
        self.user_id = -1
        self.expires_in = 0
        self.oauth_verifier = ''
        self.temp_oauth_token = ''
        self.temp_oauth_token_secret = ''
        log.info('KuaiPanAPI.__init__ by username = %s ' % username)
       
    def _server_sign(self, http_method='GET', base_uri='', parameters={}, oauth_token_secret=None):
        url = "%s/get_oauth_signature?base_uri=%s&http_method=%s&" %(self.secret_server, base_uri, http_method)
        if oauth_token_secret is not None:
            url += "oauth_token_secret=%s&" % oauth_token_secret
        url += encode(parameters)
        resp = self._readjson(url)
        if type(resp) is dict:
            return resp.get('oauth_signature')
        return ''

    def _client_sign(self, http_method='GET', base_uri='', parameters={}, oauth_token_secret=''):
        base_uri = encode(base_uri, ':/')
        return _sign(self.consumer_secret, http_method, base_uri, parameters, oauth_token_secret)

    def _request_sign(self, http_method='GET', base_uri='', parameters={}, oauth_token_secret=''):
        if self.sign_by_cleint:
            return self._client_sign(http_method, base_uri, parameters, oauth_token_secret)
        return self._server_sign(http_method, base_uri, parameters, oauth_token_secret)

    def _make_url(self, base_uri='', parameters={}, oauth_token_secret=None, http_method='GET'):
        param = parameters.copy()
        if oauth_token_secret is None:
            oauth_token_secret = self.oauth_token_secret
        param['oauth_signature'] = self._request_sign(http_method=http_method, base_uri=base_uri, parameters=parameters, oauth_token_secret=oauth_token_secret)
        return encode(base_uri, ':/.-_~') + '?' +"&".join(encode(param, '/%.-_~'))

    def _oauth_param(self):
        return {'oauth_nonce': randstr(31),
                 'oauth_timestamp': str(int(time.time()) + self.difftime),
                 'oauth_consumer_key': self.consumer_key,
                 'oauth_signature_method': 'HMAC-SHA1',
                 'oauth_version': '1.0',
                 'oauth_token': self.oauth_token}
         
    def requestToken(self):
        base_uri = "https://openapi.kuaipan.cn/open/requestToken"
        param = self._oauth_param()
        param['oauth_callback'] = self.oauth_callback
        param.pop('oauth_token')
        url = self._make_url(base_uri, param, '')
        resp = self._readjson(url)
        if type(resp) is dict:
            self.temp_oauth_token = resp.get('oauth_token')
            self.temp_oauth_token_secret = resp.get('oauth_token_secret')

    def authorize(self):
        import urllib2, urlparse, re, cookielib
        class RedirectHandler(urllib2.HTTPRedirectHandler):
            def __init__(self, kuaipan):
                self.kuaipan = kuaipan
            def _get_verifier(self, headers):
                location = headers.get('location', '')
                redirect_url = urlparse.urlparse(location)
                param = urlparse.parse_qs(redirect_url.query)
                if self.kuaipan.temp_oauth_token == param.get('oauth_token', [''])[0]:
                    self.kuaipan.oauth_verifier = param.get('oauth_verifier', [''])[0]
            def http_error_301(self, req, fp, code, msg, headers):
                self._get_verifier(headers)
                return urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)
            def http_error_302(self, req, fp, code, msg, headers):
                self._get_verifier(headers)
                return urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)
                 
        cj = cookielib.LWPCookieJar()
        cookie_support = urllib2.HTTPCookieProcessor(cj)
        opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler, RedirectHandler(self))
        #request login page
        url = 'https://www.kuaipan.cn/api.php?ac=open&op=authorise&oauth_token=' + self.temp_oauth_token
        try:
            login_page, _ = readurl(url, opener=opener)
        except Exception, e:
            print e
            return False
        #auto login
        hiddens = re.findall(r'<input\s+type="hidden"\s+name="(?P<name>\w*)"\s+value="(?P<value>\w*)"\s*/?>', login_page)
        data = {n: v for n, v in hiddens}
        data['username'] = self.username
        data['userpwd'] = self.userpwd
        data = '&'.join(encode(data))
        referer = url
        url = 'https://www.kuaipan.cn/api.php?ac=open&op=authorisecheck'
        try:
            data, _ = readurl(url, data, referer, opener)
            print data
        except Exception, e:
            log.debug(e)
        return True

    def _readjson(self, url):
        data, status = readurl(url)
        check_status(status, data)
        return loadjson(data)

    def _client_access_token(self):
        base_uri = "https://openapi.kuaipan.cn/open/accessToken"
        param = self._oauth_param()
        param['oauth_token'] = self.temp_oauth_token
        param['oauth_verifier'] = self.oauth_verifier
        url = self._make_url(base_uri, param, self.temp_oauth_token_secret)
        return self._readjson(url)

    def _server_access_token(self):
        base_uri = "%s/get_access_token?" % self.secret_server
        param = {'oauth_token' : self.temp_oauth_token,
                 'oauth_token_secret' : self.temp_oauth_token_secret,
                 'oauth_verifier' : self.oauth_verifier}
        url = base_uri + encode(param)
        return self._readjson(url)
        
    @classmethod    
    def openTime(cls):
        url = 'http://openapi.kuaipan.cn/open/time'
        data, status = readurl(url)
        check_status(status, data)
        return loadjson(data)
    
    def accessToken(self):
        if self.sign_by_cleint:
            resp = self._client_access_token()
        else:
            resp = self._server_access_token()
        if type(resp) is dict:
            self.oauth_token = resp.get('oauth_token')
            self.charged_dir = resp.get('charged_dir')
            self.user_id = resp.get('user_id')
            self.expires_in = resp.get('expires_in')
            if self.sign_by_cleint:
                self.oauth_token_secret = resp.get('oauth_token_secret')
                if self.secret_keeper:
                    self.secret_keeper(self.oauth_token, self.oauth_token_secret)
            return True
        return False
    
    def account_info(self):
        base_uri = "http://openapi.kuaipan.cn/1/account_info"
        param = self._oauth_param()
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def metadata(self, path='/'):
        base_uri = "http://openapi.kuaipan.cn/1/metadata/" + self.root + path
        param = self._oauth_param()
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def shares(self, path, name=None, access_code=None):
        base_uri = "http://openapi.kuaipan.cn/1/shares/" + self.root + path
        param = self._oauth_param()
        if name is not None:
            param['name'] = name
        if access_code is not None:
            param['access_code'] = access_code
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def history(self, path):
        base_uri = "http://openapi.kuaipan.cn/1/history/" + self.root + path
        param = self._oauth_param()
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def fileops_create_folder(self, path):
        base_uri = "http://openapi.kuaipan.cn/1/fileops/create_folder"
        param = self._oauth_param()
        param['root'] = self.root
        param['path'] = path.encode('utf-8')
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def fileops_delete(self, path, to_recycle=True):
        base_uri = "http://openapi.kuaipan.cn/1/fileops/delete"
        param = self._oauth_param()
        param['root'] = self.root
        param['path'] = path.encode('utf-8')
        param['to_recycle'] = 'true' if to_recycle else 'false'
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def fileops_move(self, to_path, from_path):
        base_uri = "http://openapi.kuaipan.cn/1/fileops/move"
        param = self._oauth_param()
        param['root'] = self.root
        param['from_path'] = from_path.encode('utf-8')
        param['to_path'] = to_path.encode('utf-8')
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def fileops_copy(self, to_path, from_path, from_copy_ref=None):
        base_uri = "http://openapi.kuaipan.cn/1/fileops/copy"
        param = self._oauth_param()
        param['root'] = self.root
        if from_path is not None:
            param['from_path'] = from_path.encode('utf-8')
        else:
            param['from_copy_ref'] = from_copy_ref
        param['to_path'] = to_path.encode('utf-8')
        url = self._make_url(base_uri, param)
        return self._readjson(url)
    
    def copy_ref(self, path):
        base_uri = "http://openapi.kuaipan.cn/1/copy_ref/" + self.root + path
        param = self._oauth_param()
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def upload_locate(self):
        base_uri = "http://api-content.dfs.kuaipan.cn/1/fileops/upload_locate"
        param = self._oauth_param()
        url = self._make_url(base_uri, param)
        return self._readjson(url)

    def upload_file(self, url, path, f, size, overwrite=True, filename=None):
        base_uri = url + "1/fileops/upload_file"
        #base_uri = "http://127.0.0.1:8000/kuaipan/test"
        param = self._oauth_param()
        param['root'] = self.root
        param['path'] = path.encode('utf-8')
        param['overwrite'] = 'true' if overwrite else 'false'
        url = self._make_url(base_uri, param, http_method='POST')
        if filename is None:
            filename = os.path.basename(path)
        filename = filename.encode('utf-8')
        data, status = uploadfile(url, f, size, 'file', filename)
        check_status(status, data)
        return loadjson(data)
    
    def upload_file_by_id(self, url, parent_id, name, f):
        base_uri = url + "/1/fileops/upload_file_by_id"
        param = self._oauth_param()
        param['parent_id'] = parent_id
        param['name'] = name.encode('utf-8')
        url = self._make_url(base_uri, param)
        data, status = uploadfile(url, f, 'file', name)
        check_status(status, data)
        return loadjson(data)
    
    def download_file(self, path):
        base_uri = "http://api-content.dfs.kuaipan.cn/1/fileops/download_file"
        param = self._oauth_param()
        param['root'] = self.root
        param['path'] = path.encode('utf-8')
        url = self._make_url(base_uri, param)
        return openurl(url)
    
    def download_file_by_id(self, file_id, rev=0):
        base_uri = "http://api-content.dfs.kuaipan.cn/1/fileops/download_file_by_id"
        param = self._oauth_param()
        param['file_id'] = file_id
        param['rev'] = str(rev)
        url = self._make_url(base_uri, param)
        return openurl(url)

    def fileops_thumbnail(self, width, height, path):
        base_uri = "http://conv.kuaipan.cn/1/fileops/thumbnail"
        param = self._oauth_param()
        param['root'] = self.root
        param['path'] = path.encode('utf-8')
        param['width'] = width
        param['height'] = height
        url = self._make_url(base_uri, param)
        return openurl(url)

    def fileops_documentView(self, doctype, view, iszip, path):
        base_uri = "http://conv.kuaipan.cn/1/fileops/documentView"
        param = self._oauth_param()
        param['root'] = self.root
        param['path'] = path.encode('utf-8')
        param['type'] = doctype
        param['zip'] = iszip
        param['view'] = view
        url = self._make_url(base_uri, param)
        return openurl(url)

if __name__=="__main__":
    
    
    from client.settings import DBStore
    _db = DBStore('test_kuaipan.db')
    def secret_keeper(token, secret):
        _db['kuaipan_token'] = token
        _db['kuaipan_secret'] = secret
    r= KuaiPanAPI.openTime()
    difftime = int(r.get('Timestamp')) - int(time.time())
    print difftime
    kp = KuaiPanAPI(username='davidwangtf@gmail.com', difftime=difftime, userpwd='521107', consumer_key='xcABUF6z7RcvaWv7', consumer_secret='gGAqN4PoUyGqbx1K', secret_keeper=secret_keeper)
    print kp.requestToken()
    print kp.authorize()
    print kp.accessToken()
    print kp.account_info()

